﻿Public Class clsFW
    Private _initVel As Drawing.PointF
    Private _explodeTime As Single

    Private _radius As Single
    Private _color As Drawing.Color
    Private _amount As Integer
    Private _fadetime As Single

    Private _partList As List(Of clsParticle)
    Private WithEvents _rkt As clsRocket
    Private _sparkEmitter As clsSparkEmitter

    Private _launched As Boolean
    Private _exploded As Boolean

    Public Sub New(ByVal startPos As Drawing.PointF, ByVal color As Drawing.Color, ByVal amount As Integer, ByVal fadeTime As Single)
        _rkt = New clsRocket(startPos, Drawing.Color.DimGray)

        _color = color
        _amount = amount
        _fadetime = fadeTime

        _launched = False
        _exploded = False
    End Sub

    Public Sub Launch(ByVal vel As Drawing.PointF, ByVal ignitionTime As Single, ByVal radius As Single)
        _sparkEmitter = New clsSparkEmitter(10.0)
        _rkt.Launch(vel, ignitionTime)
        _launched = True
        _radius = radius
    End Sub

    Private Sub Rocket_GoOff(ByVal pos As Drawing.PointF) Handles _rkt.GoOff
        _launched = False
        _exploded = True

        Dim x, y As Single
        Dim rndAngle, rndRadius As Single
        Dim endPos As Drawing.PointF = Nothing

        _sparkEmitter.SparkSpread = _radius * 0.35
        _sparkEmitter.Emit(pos, _radius, True)

        Dim newParticle As clsParticle = Nothing
        _partList = New List(Of clsParticle)
        For i = 0 To _amount - 1
            rndAngle = clsSim.RndDbl * (Math.PI * 2)
            rndRadius = (clsSim.RndRange(7, 100) / 100) * _radius
            x = pos.X + Math.Cos(rndAngle) * rndRadius
            y = pos.Y + Math.Sin(rndAngle) * rndRadius
            newParticle = New clsParticle(_color, pos, New PointF(x, y), (_fadetime * (clsSim.RndRange(40, 60) / 100 + 0.5)))
            _partList.Add(newParticle)
        Next

    End Sub

    Public Sub Draw(ByRef g As Drawing.Graphics)
        If _launched Then
            _sparkEmitter.Emit(_rkt.Position, 2)
            _rkt.Draw(g)
        ElseIf _exploded Then
            For i = _partList.Count - 1 To 0 Step -1
                _partList(i).Draw(g)
                If _partList(i).Faded Then
                    _partList.Remove(_partList(i))
                End If
            Next
        End If
        If _sparkEmitter IsNot Nothing Then
            _sparkEmitter.Draw(g)
        End If

    End Sub


#Region " Classes "
    Private Class clsParticle
        Private _pos As Drawing.PointF
        Private _endPos As Drawing.PointF
        Private _vel As Drawing.PointF
        Private _color As Drawing.Color

        Private _blinkOffset As Single

        Private _timeLiving As Single
        Private _lifeLength As Single

        Private Const SIZE As Single = 4

        Private _tcName As String

        Private _fading As Boolean
        Private _faded As Boolean

        Public ReadOnly Property Faded As Boolean
            Get
                Return _faded
            End Get
        End Property

        Public Sub New(ByVal color As Drawing.Color, ByVal pos As Drawing.PointF, ByVal endPos As Drawing.PointF, ByVal lifeLength As Single)
            _color = color
            _pos = pos
            _endPos = endPos
            _lifeLength = lifeLength

            _blinkOffset = clsSim.RndRange(0, 120) / 100.0

            _fading = False

            _tcName = clsSimTime.AddTimeControl("particle")
        End Sub

        Public Sub Draw(ByRef g As Drawing.Graphics)
            Try
                If _faded Then Return

                ' # Render
                Dim b As SolidBrush
                If Not _fading Then
                    b = New SolidBrush(_color)
                Else
                    'b = New SolidBrush(Color.FromArgb(((_lifeLength - _timeLiving) / _lifeLength) * 255, _color))
                    Dim a As Single = Math.Sin((_blinkOffset + _timeLiving) * 40.0) * 70 + (255 - 70)
                    a *= ((_lifeLength - _timeLiving) / _lifeLength)
                    a = Math.Max(a, 0)
                    b = New SolidBrush(Color.FromArgb(a, _color))
                End If

                g.FillEllipse(b, _pos.X, _pos.Y, SIZE, SIZE)

                ' # Update
                Dim timeDiff As Double = clsSimTime.GetTimeDifference(_tcName)
                If Not _fading Then
                    timeDiff *= 10
                    Dim diffX, diffY As Single
                    diffX = _endPos.X - _pos.X
                    diffY = _endPos.Y - _pos.Y
                    _pos.X += (_vel.X * timeDiff / 6) + diffX * Math.Min((timeDiff / _lifeLength), 1.0)
                    _pos.Y -= (_vel.Y * timeDiff / 6) - diffY * Math.Min((timeDiff / _lifeLength), 1.0)
                    _vel.X += clsSim.Wind * (timeDiff / 6)
                    _vel.Y += clsSim.GRAVITY * (timeDiff / 6)
                Else
                    _pos.X += (_vel.X * timeDiff)
                    _pos.Y -= (_vel.Y * timeDiff)
                    _vel.X += clsSim.Wind * timeDiff
                    _vel.Y += clsSim.GRAVITY * timeDiff
                End If
                _timeLiving += timeDiff

                If _timeLiving >= _lifeLength Then
                    If Not _fading Then
                        _fading = True
                        _timeLiving -= _lifeLength
                    Else
                        Fade()
                    End If
                End If
            Catch ex As Exception
                MsgBox(ex.ToString)
            End Try
            
        End Sub

        Private Sub Fade()
            clsSimTime.RemoveTimeControl(_tcName)
            _faded = True
        End Sub
    End Class


    Private Class clsRocket
        Private _pos As Drawing.PointF
        Private _vel As Drawing.PointF
        Private _color As Drawing.Color

        Private _timeLiving As Single
        Private _ignitionTime As Single

        Private Const LENGTH As Single = 1.0
        Private Const WIDTH As Single = 2.0

        Private _exploded As Boolean

        Private _tcName As String

        Public Event GoOff(ByVal pos As Drawing.PointF)

        Public ReadOnly Property Position As Drawing.PointF
            Get
                Return _pos
            End Get
        End Property


        Public Sub New(ByVal startPos As Drawing.PointF, ByVal color As Drawing.Color)
            _pos = startPos
            _color = color
        End Sub

        Public Sub Launch(ByVal vel As Drawing.PointF, ByVal ignitionTime As Single)
            _vel = vel
            _ignitionTime = ignitionTime
            _tcName = clsSimTime.AddTimeControl("rocket")
        End Sub

        Public Sub Draw(ByRef g As Drawing.Graphics)
            Try
                If _exploded Then Return

                ' # Render
                Dim angle As Single = Math.Atan2(-_vel.Y, _vel.X)
                Dim x1, y1, x2, y2 As Single
                x1 = _pos.X + Math.Cos(angle) * (LENGTH / 2)
                y1 = _pos.Y + Math.Sin(angle) * (LENGTH / 2)
                x2 = _pos.X - Math.Cos(angle) * (LENGTH / 2)
                y2 = _pos.Y - Math.Sin(angle) * (LENGTH / 2)
                g.DrawLine(New Drawing.Pen(_color, WIDTH), x1, y1, x2, y2)


                ' # Update
                Dim timeDiff As Double = clsSimTime.GetTimeDifference(_tcName)
                ' Move
                _pos.X += _vel.X * timeDiff
                _pos.Y -= _vel.Y * timeDiff
                _vel.X += clsSim.Wind * timeDiff
                _vel.Y += clsSim.GRAVITY * timeDiff
                ' Age
                _timeLiving += timeDiff
                If _timeLiving >= _ignitionTime Then
                    Explode()
                End If
            Catch ex As Exception
                MsgBox(ex.ToString)
            End Try
        End Sub

        Private Sub Explode()
            _exploded = True
            clsSimTime.RemoveTimeControl(_tcName)
            RaiseEvent GoOff(_pos)
        End Sub
    End Class
#End Region
    
End Class
